﻿/*
* 创建者：LIYINFAI
* 创建时间：2023/10/24 9:35:26
* 描述：
* --------------------------------------
* 修改说明：
* 三菱的PLC需要多开几个端口
* 常规以 6000 开始 
* Single 	6000
* BatchPLC 	6001
* MRead		6000
* MWrite    6002
* 耐压：6003,6004,6005,6006,6007
* 绝缘：6008,6009,6010,6011,6012
* --------------------------------------
*/
using HslCommunication;
using HslCommunication.Core.Net;
using HslCommunication.Profinet.AllenBradley;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;

namespace CommonLibrary
{
    /// <summary>
    /// PLC操作类
    /// </summary>
    public class PLCHelper
    {
        /// <summary>
        /// 是否单个连接
        /// </summary>
        private bool mIsSingle = true;

        /// <summary>
        /// 批量读取时是否分批读取
        /// </summary>
        private bool mSplitBatchRead = true;
        /// <summary>
        /// 是否自检
        /// </summary>
        private bool mIsNeedSelfCheck = false;
        /// <summary>
        /// 获取IP端口字符串
        /// </summary>
        /// <returns></returns>
        public string GetIPPort()
        {
            return $"{(this.mPLCEntity != null ? this.mPLCEntity.IP : "")}{(this.mPLCEntity != null ? ":" + this.mPLCEntity.Port : "")}";
        }
        /// <summary>
        /// 描述信息
        /// </summary>
        /// <returns></returns>
        public override string ToString()
        {
            if (this.mPLCEntity == null)
            {
                return "PLC未配置或错误配置";
            }
            else
            {
                return $"IP: {this.mPLCEntity.IP}, Port:{this.mPLCEntity.Port}, Type: {this.mPLCEntity.OptType}";
            }
        }
        /// <summary>
        /// 配置文件
        /// </summary>
        static string configPath = Path.Combine(CommonHelper.COMMON_CONFIG_DIR, "PLCV2Config.json");
        /// <summary>
        /// 获取配置内容
        /// </summary>
        /// <returns></returns>
        public static PLCEntity GetPLCConfig()
        {
            return CommonHelper.GetJsonFromFile<PLCEntity>(configPath, new PLCEntity());
        }
        /// <summary>
        /// 保存配置内容
        /// </summary>
        /// <param name="entity"></param>
        public static void SavePLCConfig(PLCEntity entity)
        {
            CommonHelper.SaveToJsonFile(entity, configPath);
        }

        private PLCEntity mPLCEntity = null;
        private Encoding mEncoding = Encoding.UTF8;
        private NetworkDeviceBase mSinglePLCNet = null;
        private NetworkDeviceBase mBatchPLCNet = null;
        private NetworkDeviceBase mMultiReadPLCNet = null;
        private NetworkDeviceBase mMultiWritePLCNet = null;
        private NetworkDeviceBase mScanPLCNet1 = null;//6003
        private NetworkDeviceBase mScanPLCNet2 = null; //6004
        private NetworkDeviceBase mScanPLCNet3 = null; //6005
        private NetworkDeviceBase mScanPLCNet4 = null; //6006
        private NetworkDeviceBase mScanPLCNet5 = null; //6007
        private NetworkDeviceBase mHiPLCNet1 = null;//6008
        private NetworkDeviceBase mHiPLCNet2 = null;//6009
        private NetworkDeviceBase mHiPLCNet3 = null;//6010
        private NetworkDeviceBase mHiPLCNet4 = null;//6011
        private NetworkDeviceBase mHiPLCNet5 = null;//6012
        private Socket mSocket = null;
        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            if (this.mIsSingle)
            {
                SingleInit();
            }
            else
            {
                MultiInit();
            }
        }
        /// <summary>
        /// 初始化
        /// </summary>
        private void BatchReadInit()
        {
            if (this.mBatchPLCNet != null)
            {
                try
                {
                    this.mBatchPLCNet.ConnectClose();
                    this.mBatchPLCNet = null;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            switch (this.mPLCEntity.DeviceType)
            {
                case EPLCDeviceType.OMRON:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var orNet1 = new HslCommunication.Profinet.Omron.OmronFinsNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        orNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        orNet1.SetPersistentConnection();
                        this.mBatchPLCNet = orNet1;
                    }
                    else
                    {
                        var orcNet1 = new HslCommunication.Profinet.Omron.OmronCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        orcNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        orcNet1.SetPersistentConnection();
                        this.mBatchPLCNet = orcNet1;
                    }
                    break;
                case EPLCDeviceType.INOVANCE:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var inoNet1 = new HslCommunication.Profinet.Inovance.InovanceTcpNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        inoNet1.IsStringReverse = this.mPLCEntity.IsStringReserve;
                        inoNet1.SetPersistentConnection();
                        this.mBatchPLCNet = inoNet1;
                    }
                    break;
                case EPLCDeviceType.MELSEC:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var meNet1 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 1);
                        meNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet1.TargetIOStation = 0x03FF;
                        meNet1.NetworkNumber = 0x00;  // 网络号
                        meNet1.NetworkStationNumber = 0x00; // 网络站号
                        meNet1.SetPersistentConnection();
                        this.mBatchPLCNet = meNet1;
                    }
                    else
                    {
                        var mecNet1 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 1);
                        mecNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet1.SetPersistentConnection();
                        this.mBatchPLCNet = mecNet1;
                    }
                    break;
            }
            if (this.mBatchPLCNet != null && this.mPLCEntity.DeviceType != EPLCDeviceType.MELSEC)
            {
                this.mBatchPLCNet.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                try
                {
                    OperateResult operateResult1 = this.mBatchPLCNet.ConnectServer();
                    if (operateResult1 == null || !operateResult1.IsSuccess)
                    {
                        this.mBatchPLCNet = null;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void SingleInit()
        {
            if (this.mSinglePLCNet != null)
            {
                try
                {
                    this.mSinglePLCNet.ConnectClose();
                    this.mSinglePLCNet = null;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            switch (this.mPLCEntity.DeviceType)
            {
                case EPLCDeviceType.OMRON:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var orNet1 = new HslCommunication.Profinet.Omron.OmronFinsNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        orNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        orNet1.SetPersistentConnection();
                        this.mSinglePLCNet = orNet1;
                    }
                    else
                    {
                        var orcNet1 = new HslCommunication.Profinet.Omron.OmronCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        orcNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        orcNet1.SetPersistentConnection();
                        this.mSinglePLCNet = orcNet1;
                    }
                    break;
                case EPLCDeviceType.INOVANCE:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var inoNet1 = new HslCommunication.Profinet.Inovance.InovanceTcpNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        inoNet1.IsStringReverse = this.mPLCEntity.IsStringReserve;
                        inoNet1.SetPersistentConnection();
                        this.mSinglePLCNet = inoNet1;
                    }
                    break;
                case EPLCDeviceType.MELSEC:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var meNet1 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        meNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet1.TargetIOStation = 0x03FF;
                        meNet1.NetworkNumber = 0x00;  // 网络号
                        meNet1.NetworkStationNumber = 0x00; // 网络站号
                        meNet1.SetPersistentConnection();
                        this.mSinglePLCNet = meNet1;
                    }
                    else
                    {
                        var mecNet1 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        mecNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet1.SetPersistentConnection();
                        this.mSinglePLCNet = mecNet1;
                    }
                    break;
            }
            if (this.mSinglePLCNet != null)
            {
                this.mSinglePLCNet.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                try
                {
                    OperateResult operateResult1 = this.mSinglePLCNet.ConnectServer();
                    if (operateResult1 == null || !operateResult1.IsSuccess)
                    {
                        this.mIsConnected = false;
                        this.mSinglePLCNet = null;
                    }
                    else
                    {
                        this.mIsConnected = true;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
        }
        private void MultiInit()
        {
            if (this.mMultiReadPLCNet != null)
            {
                try
                {
                    this.mMultiReadPLCNet.ConnectClose();
                    this.mMultiReadPLCNet = null;
                    this.mMultiWritePLCNet.ConnectClose();
                    this.mMultiWritePLCNet = null;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            if (this.mScanPLCNet1 != null)
            {
                try
                {
                    this.mScanPLCNet1.ConnectClose();
                    this.mScanPLCNet1 = null;
                    this.mScanPLCNet2.ConnectClose();
                    this.mScanPLCNet2 = null;
                    this.mScanPLCNet3.ConnectClose();
                    this.mScanPLCNet3 = null;
                    this.mScanPLCNet4.ConnectClose();
                    this.mScanPLCNet4 = null;
                    this.mScanPLCNet5.ConnectClose();
                    this.mScanPLCNet5 = null;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            if (this.mHiPLCNet1 != null)
            {
                try
                {
                    this.mHiPLCNet1.ConnectClose();
                    this.mHiPLCNet1 = null;
                    this.mHiPLCNet2.ConnectClose();
                    this.mHiPLCNet2 = null;
                    this.mHiPLCNet3.ConnectClose();
                    this.mHiPLCNet3 = null;
                    this.mHiPLCNet4.ConnectClose();
                    this.mHiPLCNet4 = null;
                    this.mHiPLCNet5.ConnectClose();
                    this.mHiPLCNet5 = null;
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            switch (this.mPLCEntity.DeviceType)
            {
                case EPLCDeviceType.OMRON:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var orNet1 = new HslCommunication.Profinet.Omron.OmronFinsNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        orNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        orNet1.SetPersistentConnection();
                        this.mMultiReadPLCNet = orNet1;
                        var orNet2 = new HslCommunication.Profinet.Omron.OmronFinsNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        orNet2.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        orNet2.SetPersistentConnection();
                        this.mMultiWritePLCNet = orNet2;
                    }
                    else
                    {
                        var orcNet1 = new HslCommunication.Profinet.Omron.OmronCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        orcNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        orcNet1.SetPersistentConnection();
                        this.mMultiReadPLCNet = orcNet1;
                        var orcNet2 = new HslCommunication.Profinet.Omron.OmronCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        orcNet2.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        orcNet2.SetPersistentConnection();
                        this.mMultiWritePLCNet = orcNet2;
                    }
                    break;
                case EPLCDeviceType.INOVANCE:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var inoNet1 = new HslCommunication.Profinet.Inovance.InovanceTcpNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        inoNet1.IsStringReverse = this.mPLCEntity.IsStringReserve;
                        inoNet1.SetPersistentConnection();
                        this.mMultiReadPLCNet = inoNet1;
                        var inoNet2 = new HslCommunication.Profinet.Inovance.InovanceTcpNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        inoNet2.IsStringReverse = this.mPLCEntity.IsStringReserve;
                        inoNet2.SetPersistentConnection();
                        this.mMultiWritePLCNet = inoNet2;
                    }
                    break;
                case EPLCDeviceType.MELSEC:
                    if (this.mPLCEntity.OptType == EPLCOptType.FINS)
                    {
                        var meNet1 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        meNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet1.TargetIOStation = 0x03FF;
                        meNet1.NetworkNumber = 0x00;  // 网络号
                        meNet1.NetworkStationNumber = 0x00; // 网络站号
                        meNet1.SetPersistentConnection();
                        this.mMultiReadPLCNet = meNet1;

                        var meNet2 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 2);
                        meNet2.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet2.TargetIOStation = 0x03FF;
                        meNet2.NetworkNumber = 0x00;  // 网络号
                        meNet2.NetworkStationNumber = 0x00; // 网络站号
                        meNet2.SetPersistentConnection();
                        this.mMultiWritePLCNet = meNet2;


                        var meNet31 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 3);
                        meNet31.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet31.TargetIOStation = 0x03FF;
                        meNet31.NetworkNumber = 0x00;  // 网络号
                        meNet31.NetworkStationNumber = 0x00; // 网络站号
                        meNet31.SetPersistentConnection();
                        this.mScanPLCNet1 = meNet31;


                        var meNet32 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 4);
                        meNet32.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet32.TargetIOStation = 0x03FF;
                        meNet32.NetworkNumber = 0x00;  // 网络号
                        meNet32.NetworkStationNumber = 0x00; // 网络站号
                        meNet32.SetPersistentConnection();
                        this.mScanPLCNet2 = meNet32;

                        var meNet33 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 5);
                        meNet33.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet33.TargetIOStation = 0x03FF;
                        meNet33.NetworkNumber = 0x00;  // 网络号
                        meNet33.NetworkStationNumber = 0x00; // 网络站号
                        meNet33.SetPersistentConnection();
                        this.mScanPLCNet3 = meNet33;

                        var meNet34 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 6);
                        meNet34.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet34.TargetIOStation = 0x03FF;
                        meNet34.NetworkNumber = 0x00;  // 网络号
                        meNet34.NetworkStationNumber = 0x00; // 网络站号
                        meNet34.SetPersistentConnection();
                        this.mScanPLCNet4 = meNet34;

                        var meNet35 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 7);
                        meNet35.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet35.TargetIOStation = 0x03FF;
                        meNet35.NetworkNumber = 0x00;  // 网络号
                        meNet35.NetworkStationNumber = 0x00; // 网络站号
                        meNet35.SetPersistentConnection();
                        this.mScanPLCNet5 = meNet35;

                        var meNet41 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 8);
                        meNet41.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet41.TargetIOStation = 0x03FF;
                        meNet41.NetworkNumber = 0x00;  // 网络号
                        meNet41.NetworkStationNumber = 0x00; // 网络站号
                        meNet41.SetPersistentConnection();
                        this.mHiPLCNet1 = meNet41;

                        var meNet42 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 9);
                        meNet42.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet42.TargetIOStation = 0x03FF;
                        meNet42.NetworkNumber = 0x00;  // 网络号
                        meNet42.NetworkStationNumber = 0x00; // 网络站号
                        meNet42.SetPersistentConnection();
                        this.mHiPLCNet2 = meNet42;

                        var meNet43 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 10);
                        meNet43.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet43.TargetIOStation = 0x03FF;
                        meNet43.NetworkNumber = 0x00;  // 网络号
                        meNet43.NetworkStationNumber = 0x00; // 网络站号
                        meNet43.SetPersistentConnection();
                        this.mHiPLCNet3 = meNet43;

                        var meNet44 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 11);
                        meNet44.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet44.TargetIOStation = 0x03FF;
                        meNet44.NetworkNumber = 0x00;  // 网络号
                        meNet44.NetworkStationNumber = 0x00; // 网络站号
                        meNet44.SetPersistentConnection();
                        this.mHiPLCNet4 = meNet44;

                        var meNet45 = new HslCommunication.Profinet.Melsec.MelsecMcNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 12);
                        meNet45.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        meNet45.TargetIOStation = 0x03FF;
                        meNet45.NetworkNumber = 0x00;  // 网络号
                        meNet45.NetworkStationNumber = 0x00; // 网络站号
                        meNet45.SetPersistentConnection();
                        this.mHiPLCNet5 = meNet45;
                    }
                    else
                    {
                        var mecNet1 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port);
                        mecNet1.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet1.SetPersistentConnection();
                        this.mMultiReadPLCNet = mecNet1;

                        var mecNet2 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 2);
                        mecNet2.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet2.SetPersistentConnection();
                        this.mMultiWritePLCNet = mecNet2;


                        var mecNet31 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 3);
                        mecNet31.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet31.SetPersistentConnection();
                        this.mScanPLCNet1 = mecNet31;

                        var mecNet32 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 4);
                        mecNet32.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet32.SetPersistentConnection();
                        this.mScanPLCNet2 = mecNet32;

                        var mecNet33 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 5);
                        mecNet33.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet33.SetPersistentConnection();
                        this.mScanPLCNet3 = mecNet33;

                        var mecNet34 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 6);
                        mecNet34.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet34.SetPersistentConnection();
                        this.mScanPLCNet4 = mecNet34;

                        var mecNet35 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 7);
                        mecNet35.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet35.SetPersistentConnection();
                        this.mScanPLCNet5 = mecNet35;

                        var mecNet41 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 8);
                        mecNet41.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet41.SetPersistentConnection();
                        this.mHiPLCNet1 = mecNet41;

                        var mecNet42 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 9);
                        mecNet42.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet42.SetPersistentConnection();
                        this.mHiPLCNet2 = mecNet42;

                        var mecNet43 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 10);
                        mecNet43.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet43.SetPersistentConnection();
                        this.mHiPLCNet3 = mecNet43;

                        var mecNet44 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 11);
                        mecNet44.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet44.SetPersistentConnection();
                        this.mHiPLCNet4 = mecNet44;

                        var mecNet45 = new HslCommunication.Profinet.Melsec.MelsecCipNet(this.mPLCEntity.IP, this.mPLCEntity.Port + 12);
                        mecNet45.ByteTransform.IsStringReverseByteWord = this.mPLCEntity.IsStringReserve;
                        mecNet45.SetPersistentConnection();
                        this.mHiPLCNet5 = mecNet45;
                    }
                    break;
            }
            if (this.mMultiReadPLCNet != null)
            {
                this.mMultiReadPLCNet.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                this.mMultiWritePLCNet.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;

                if (this.mScanPLCNet1 != null)
                {
                    this.mScanPLCNet1.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                if (this.mScanPLCNet2 != null)
                {
                    this.mScanPLCNet2.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                if (this.mScanPLCNet3 != null)
                {
                    this.mScanPLCNet3.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                if (this.mScanPLCNet4 != null)
                {
                    this.mScanPLCNet4.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                if (this.mScanPLCNet5 != null)
                {
                    this.mScanPLCNet5.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }

                if (this.mHiPLCNet1 != null)
                {
                    this.mHiPLCNet1.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                if (this.mHiPLCNet2 != null)
                {
                    this.mHiPLCNet2.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                if (this.mHiPLCNet3 != null)
                {
                    this.mHiPLCNet3.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                if (this.mHiPLCNet4 != null)
                {
                    this.mHiPLCNet4.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                if (this.mHiPLCNet5 != null)
                {
                    this.mHiPLCNet5.ConnectTimeOut = this.mPLCEntity.ConnectTimeOut;
                }
                try
                {
                    OperateResult op1 = this.mMultiReadPLCNet.ConnectServer();
                    OperateResult op2 = this.mMultiWritePLCNet.ConnectServer();

                    OperateResult op31 = this.mScanPLCNet1 == null ? OperateResult.CreateSuccessResult() : this.mScanPLCNet1.ConnectServer();
                    OperateResult op32 = this.mScanPLCNet2 == null ? OperateResult.CreateSuccessResult() : this.mScanPLCNet2.ConnectServer();
                    OperateResult op33 = this.mScanPLCNet3 == null ? OperateResult.CreateSuccessResult() : this.mScanPLCNet3.ConnectServer();
                    OperateResult op34 = this.mScanPLCNet4 == null ? OperateResult.CreateSuccessResult() : this.mScanPLCNet4.ConnectServer();
                    OperateResult op35 = this.mScanPLCNet5 == null ? OperateResult.CreateSuccessResult() : this.mScanPLCNet5.ConnectServer();

                    OperateResult op41 = this.mHiPLCNet1 == null ? OperateResult.CreateSuccessResult() : this.mHiPLCNet1.ConnectServer();
                    OperateResult op42 = this.mHiPLCNet2 == null ? OperateResult.CreateSuccessResult() : this.mHiPLCNet2.ConnectServer();
                    OperateResult op43 = this.mHiPLCNet3 == null ? OperateResult.CreateSuccessResult() : this.mHiPLCNet3.ConnectServer();
                    OperateResult op44 = this.mHiPLCNet4 == null ? OperateResult.CreateSuccessResult() : this.mHiPLCNet4.ConnectServer();
                    OperateResult op45 = this.mHiPLCNet5 == null ? OperateResult.CreateSuccessResult() : this.mHiPLCNet5.ConnectServer();

                    if (op1 == null || !op1.IsSuccess
                        || op2 == null || !op2.IsSuccess
                        || op31 == null || !op31.IsSuccess
                        || op32 == null || !op32.IsSuccess
                        || op33 == null || !op33.IsSuccess
                        || op34 == null || !op34.IsSuccess
                        || op35 == null || !op35.IsSuccess
                        || op41 == null || !op41.IsSuccess
                        || op42 == null || !op42.IsSuccess
                        || op43 == null || !op43.IsSuccess
                        || op44 == null || !op44.IsSuccess
                        || op45 == null || !op45.IsSuccess)
                    {
                        if (this.mMultiReadPLCNet != null && this.mMultiWritePLCNet != null)
                        {
                            LogHelper.Error(null, "【PLC连接异常】", $"【{this.mMultiReadPLCNet.IpAddress}:{this.mMultiReadPLCNet.Port} - {op1.IsSuccess}】【{this.mMultiWritePLCNet.IpAddress}:{this.mMultiWritePLCNet.Port} - {op2.IsSuccess}】");
                        }
                        this.mIsConnected = false;
                        this.mMultiReadPLCNet = null;
                        this.mMultiWritePLCNet = null;
                        this.mScanPLCNet1 = null;
                        this.mScanPLCNet2 = null;
                        this.mScanPLCNet3 = null;
                        this.mScanPLCNet4 = null;
                        this.mScanPLCNet5 = null;

                        this.mHiPLCNet1 = null;
                        this.mHiPLCNet2 = null;
                        this.mHiPLCNet3 = null;
                        this.mHiPLCNet4 = null;
                        this.mHiPLCNet5 = null;
                    }
                    else
                    {
                        this.mIsConnected = true;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
        }
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="entity"></param>
        public PLCHelper(PLCEntity entity)
        {
            this.mPLCEntity = entity;
            this.mIsSingle = entity.IsSingle;
            this.mSplitBatchRead = entity.IsSplitBatchRead;
            this.mEncoding = string.IsNullOrWhiteSpace(entity.StringEncoding) ? this.mEncoding : Encoding.GetEncoding(entity.StringEncoding);
            Init();
            this.mIsNeedSelfCheck = true;
            new Thread(() =>
            {
                while (this.mIsNeedSelfCheck)
                {
                    if (this.mSinglePLCNet == null && this.mIsSingle)
                    {
                        SingleInit();
                    }
                    else if ((this.mMultiReadPLCNet == null || this.mMultiWritePLCNet == null) && !this.mIsSingle)
                    {
                        MultiInit();
                    }
                    else
                    {
                        try
                        {
                            if (this.mPLCEntity.DeviceType == EPLCDeviceType.MELSEC)
                            {
                                if (this.mSinglePLCNet != null)
                                {
                                    IPStatus pingStatus = this.mSinglePLCNet.IpAddressPing();
                                    this.mIsConnected = pingStatus == IPStatus.Success;
                                }
                                else if (this.mMultiReadPLCNet != null)
                                {
                                    IPStatus pingStatus = this.mMultiReadPLCNet.IpAddressPing();
                                    this.mIsConnected = pingStatus == IPStatus.Success;
                                }
                            }
                            else
                            {
                                this.mSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                                var asyncResult = this.mSocket.BeginConnect(this.mPLCEntity.IP, this.mPLCEntity.Port, null, null);
                                bool success = asyncResult.AsyncWaitHandle.WaitOne(500, true);
                                if (this.mSocket.Connected)
                                {
                                    this.mSocket.EndConnect(asyncResult);
                                }
                                this.mIsConnected = this.mSocket.Connected;
                                this.mSocket.Close();
                            }
                        }
                        catch (Exception ex)
                        {
                            LogHelper.Error(ex);
                        }
                    }
                    if (this.mBatchPLCNet == null)
                    {
                        BatchReadInit();
                    }
                    Thread.Sleep(1000);
                }
            }).Start();
        }
        /// <summary>
        /// 是否连接
        /// </summary>
        public bool IsConnected => mIsConnected;
        private bool mIsConnected = false;
        /// <summary>
        /// 断开连接
        /// </summary>
        public void Disconnect()
        {
            this.mIsNeedSelfCheck = false;
            try
            {
                if (this.mBatchPLCNet != null)
                {
                    try
                    {
                        this.mBatchPLCNet.ConnectClose();
                        this.mBatchPLCNet = null;
                    }
                    catch (Exception ex0)
                    {
                        LogHelper.Error(ex0);
                    }
                }

                if (this.mSinglePLCNet != null)
                {
                    try
                    {
                        this.mSinglePLCNet.ConnectClose();
                        this.mSinglePLCNet = null;
                    }
                    catch (Exception ex1)
                    {
                        LogHelper.Error(ex1);
                    }
                }

                if (this.mMultiReadPLCNet != null)
                {
                    try
                    {
                        this.mMultiReadPLCNet.ConnectClose();
                        this.mMultiReadPLCNet = null;
                    }
                    catch (Exception ex2)
                    {
                        LogHelper.Error(ex2);
                    }
                }

                if (this.mMultiWritePLCNet != null)
                {
                    try
                    {
                        this.mMultiWritePLCNet.ConnectClose();
                        this.mMultiWritePLCNet = null;
                    }
                    catch (Exception ex3)
                    {
                        LogHelper.Error(ex3);
                    }
                }
                if (this.mScanPLCNet1 != null)
                {
                    try
                    {
                        this.mScanPLCNet1.ConnectClose();
                        this.mScanPLCNet1 = null;
                    }
                    catch (Exception ex4)
                    {
                        LogHelper.Error(ex4);
                    }
                }
                if (this.mScanPLCNet2 != null)
                {
                    try
                    {
                        this.mScanPLCNet2.ConnectClose();
                        this.mScanPLCNet2 = null;
                    }
                    catch (Exception ex4)
                    {
                        LogHelper.Error(ex4);
                    }
                }
                if (this.mScanPLCNet3 != null)
                {
                    try
                    {
                        this.mScanPLCNet3.ConnectClose();
                        this.mScanPLCNet3 = null;
                    }
                    catch (Exception ex4)
                    {
                        LogHelper.Error(ex4);
                    }
                }
                if (this.mScanPLCNet4 != null)
                {
                    try
                    {
                        this.mScanPLCNet4.ConnectClose();
                        this.mScanPLCNet4 = null;
                    }
                    catch (Exception ex4)
                    {
                        LogHelper.Error(ex4);
                    }
                }
                if (this.mScanPLCNet5 != null)
                {
                    try
                    {
                        this.mScanPLCNet5.ConnectClose();
                        this.mScanPLCNet5 = null;
                    }
                    catch (Exception ex4)
                    {
                        LogHelper.Error(ex4);
                    }
                }

                if (this.mHiPLCNet1 != null)
                {
                    try
                    {
                        this.mHiPLCNet1.ConnectClose();
                        this.mHiPLCNet1 = null;
                    }
                    catch (Exception ex5)
                    {
                        LogHelper.Error(ex5);
                    }
                }
                if (this.mHiPLCNet2 != null)
                {
                    try
                    {
                        this.mHiPLCNet2.ConnectClose();
                        this.mHiPLCNet2 = null;
                    }
                    catch (Exception ex5)
                    {
                        LogHelper.Error(ex5);
                    }
                }
                if (this.mHiPLCNet3 != null)
                {
                    try
                    {
                        this.mHiPLCNet3.ConnectClose();
                        this.mHiPLCNet3 = null;
                    }
                    catch (Exception ex5)
                    {
                        LogHelper.Error(ex5);
                    }
                }
                if (this.mHiPLCNet4 != null)
                {
                    try
                    {
                        this.mHiPLCNet4.ConnectClose();
                        this.mHiPLCNet4 = null;
                    }
                    catch (Exception ex5)
                    {
                        LogHelper.Error(ex5);
                    }
                }
                if (this.mHiPLCNet5 != null)
                {
                    try
                    {
                        this.mHiPLCNet5.ConnectClose();
                        this.mHiPLCNet5 = null;
                    }
                    catch (Exception ex5)
                    {
                        LogHelper.Error(ex5);
                    }
                }
                if (this.mSocket != null && this.mSocket.Connected)
                {
                    this.mSocket.Close();
                    this.mSocket.Dispose();
                    this.mSocket = null;
                }
            }
            catch (Exception ex)
            {
                LogHelper.Error(ex);
            }
        }
        private NetworkDeviceBase GetBatchReader()
        {
            return GlobalStatus.PROGRAM == EAppStatus.RUN ? this.mBatchPLCNet : null;
        }
        private NetworkDeviceBase GetReader()
        {
            if (GlobalStatus.PROGRAM == EAppStatus.RUN)
            {
                if (this.mIsSingle)
                {
                    return this.mSinglePLCNet;
                }
                else
                {
                    return this.mMultiReadPLCNet;
                }
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 0 - 正常，1~5 - SCAN, 6~10 - 测试仪（Multiple 有效）
        /// </summary>
        /// <returns></returns>
        private NetworkDeviceBase GetWriter(int writerType = 0)
        {
            if (GlobalStatus.PROGRAM == EAppStatus.RUN)
            {
                if (this.mIsSingle)
                {
                    return this.mSinglePLCNet;
                }
                else
                {
                    NetworkDeviceBase result = this.mMultiWritePLCNet;
                    if (this.mPLCEntity != null && this.mPLCEntity.DeviceType == EPLCDeviceType.MELSEC)
                    {
                        switch (writerType)
                        {
                            case 0: result = this.mMultiWritePLCNet; break;
                            case 1: result = this.mScanPLCNet1; break;
                            case 2: result = this.mScanPLCNet2; break;
                            case 3: result = this.mScanPLCNet3; break;
                            case 4: result = this.mScanPLCNet4; break;
                            case 5: result = this.mScanPLCNet5; break;
                            case 6: result = this.mHiPLCNet1; break;
                            case 7: result = this.mHiPLCNet2; break;
                            case 8: result = this.mHiPLCNet3; break;
                            case 9: result = this.mHiPLCNet4; break;
                            case 10: result = this.mHiPLCNet5; break;
                        }
                    }
                    return result;
                }
            }
            else
            {
                return null;
            }
        }
        /// <summary>
        /// 批量读取
        /// </summary>
        /// <param name="addressList"></param>
        /// <param name="forceFullRead">是否强制全读</param>
        /// <returns></returns>
        public Dictionary<string, object> BatchRead(List<PLCTagSetting> addressList, bool forceFullRead = false)
        {
            Stopwatch stopwatch = Stopwatch.StartNew();
            LogHelper.Info($"开始批量读取");
            Dictionary<string, object> result = new Dictionary<string, object>();

            if (addressList != null && addressList.Count > 0)
            {
                if (this.mPLCEntity.OptType == EPLCOptType.CIP)
                {
                    if (forceFullRead)
                    {
                        result = BatchTagsRead(addressList);
                    }
                    else
                    {
                        if (this.mSplitBatchRead)
                        {
                            addressList = addressList.OrderBy(v => v.Tag).ToList();
                            int step = 30, tempIndex = 0;
                            while (tempIndex < addressList.Count)
                            {
                                var tempList = addressList.Skip(tempIndex).Take(step).ToList();
                                var temp = BatchTagsRead(tempList);

                                if (temp != null && temp.Count > 0)
                                {
                                    foreach (var t in temp.Keys)
                                    {
                                        if (!result.ContainsKey(t))
                                        {
                                            result.Add(t, temp[t]);
                                        }
                                    }
                                }
                                tempIndex += step;
                            }
                        }
                        else
                        {
                            result = BatchTagsRead(addressList);
                        }

                    }
                }
                else
                {
                    if (forceFullRead)
                    {
                        result = BatchAddressRead(addressList);
                    }
                    else
                    {
                        if (this.mSplitBatchRead)
                        {
                            addressList = addressList.OrderBy(v => v.Tag).ToList();
                            int step = 40, tempIndex = 0;
                            while (tempIndex < addressList.Count)
                            {
                                var tempList = addressList.Skip(tempIndex).Take(step).ToList();
                                var temp = BatchAddressRead(tempList);

                                if (temp != null && temp.Count > 0)
                                {
                                    foreach (var t in temp.Keys)
                                    {
                                        if (!result.ContainsKey(t))
                                        {
                                            result.Add(t, temp[t]);
                                        }
                                    }
                                }
                                tempIndex += step;
                            }
                        }
                        else
                        {
                            result = BatchAddressRead(addressList);
                        }
                    }
                }
            }
            stopwatch.Stop();
            LogHelper.Info($"结束批量读取，耗时：{stopwatch.ElapsedMilliseconds} 毫秒");
            return result;
        }
        /// <summary>
        /// SimpleMultiTagsRead
        /// </summary>
        /// <param name="addressList"></param>
        /// <returns></returns>
        public Dictionary<string, object> SimpleMultiTagsRead(List<PLCTagSetting> addressList)
        {
            Dictionary<string, object> result = new Dictionary<string, object>();
            var reader = this.GetBatchReader();
            if (reader != null && addressList != null && addressList.Count > 0)
            {
                foreach (var p in addressList)
                {
                    try
                    {
                        switch (p.TypeName.ToLower())
                        {
                            case "short":
                                var valShort = reader.ReadInt16(p.Tag).Content;
                                if (p.IsToFloat)
                                {
                                    result.Add(p.ORMName, (float)(valShort * 1.0f * p.div));
                                }
                                else
                                {
                                    result.Add(p.ORMName, valShort);
                                }
                                break;
                            case "ushort":
                                var valUShort = reader.ReadUInt16(p.Tag).Content;
                                if (p.IsToFloat)
                                {
                                    result.Add(p.ORMName, (float)(valUShort * 1.0f * p.div));
                                }
                                else
                                {
                                    result.Add(p.ORMName, valUShort);
                                }
                                break;
                            case "int":
                                var valInt = reader.ReadInt32(p.Tag).Content;
                                if (p.IsToFloat)
                                {
                                    result.Add(p.ORMName, (float)(valInt * 1.0f * p.div));
                                }
                                else
                                {
                                    result.Add(p.ORMName, valInt);
                                }
                                break;
                            case "uint":
                                var valUInt = reader.ReadUInt32(p.Tag).Content;
                                if (p.IsToFloat)
                                {
                                    result.Add(p.ORMName, (float)(valUInt * 1.0f * p.div));
                                }
                                else
                                {
                                    result.Add(p.ORMName, valUInt);
                                }
                                break;
                            case "long":
                                var valLong = reader.ReadInt64(p.Tag).Content;
                                if (p.IsToFloat)
                                {
                                    result.Add(p.ORMName, (float)(valLong * 1.0f * p.div));
                                }
                                else
                                {
                                    result.Add(p.ORMName, valLong);
                                }
                                break;
                            case "long8time":
                                var time = reader.ReadInt64(p.Tag).Content;
                                DateTime temp = DateTime.Parse("1970-01-01");
                                temp = temp.AddSeconds(time - 8 * 60 * 60);
                                result.Add(p.ORMName, temp.ToString("yyyy-MM-dd HH:mm:ss"));
                                break;
                            case "longtime":
                                var time1 = reader.ReadInt64(p.Tag).Content;
                                DateTime temp1 = DateTime.Parse("1970-01-01");
                                temp1 = temp1.AddSeconds(time1);
                                result.Add(p.ORMName, temp1.ToString("yyyy-MM-dd HH:mm:ss"));
                                break;
                            case "ulong":
                                var valULong = reader.ReadUInt64(p.Tag).Content;
                                if (p.IsToFloat)
                                {
                                    result.Add(p.ORMName, (float)(valULong * 1.0f * p.div));
                                }
                                else
                                {
                                    result.Add(p.ORMName, valULong);
                                }
                                break;
                            case "decimal":
                            case "float":
                                var valFloat = reader.ReadFloat(p.Tag).Content;
                                if (p.IsToFloat)
                                {
                                    result.Add(p.ORMName, (float)(valFloat * 1.0f * p.div));
                                }
                                else
                                {
                                    result.Add(p.ORMName, valFloat);
                                }
                                break;
                            case "double":
                                var valDouble = reader.ReadDouble(p.Tag).Content;
                                if (p.IsToFloat)
                                {
                                    result.Add(p.ORMName, (double)(valDouble * 1.0f * p.div));
                                }
                                else
                                {
                                    result.Add(p.ORMName, valDouble);
                                }
                                break;
                            case "string": result.Add(p.ORMName, reader.ReadString(p.Tag, (ushort)1, CommonHelper.ENCODING).Content); break;
                        }

                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                    }
                }
            }
            return result;
        }
        /// <summary>
        /// 读取多个标签，只支持标签
        /// </summary>
        /// <param name="addressList"></param>
        /// <returns></returns>
        private Dictionary<string, object> BatchTagsRead(List<PLCTagSetting> addressList)
        {
            var reader = this.GetBatchReader();
            Dictionary<string, object> result = new Dictionary<string, object>();
            if (reader != null && addressList != null && addressList.Count > 0)
            {
                List<PLCTagSetting> singleBoolTags = new List<PLCTagSetting>();
                List<PLCTagSetting> otherTags = new List<PLCTagSetting>();
                //提取BOOL类型
                List<BoolTagBelong> boolTagBelongs = new List<BoolTagBelong>();
                Regex regex = new Regex("^[0-9]+$");
                foreach (PLCTagSetting address in addressList)
                {
                    if (address.TypeName.ToLower().Equals("bool"))
                    {
                        int lastRightBracket = address.Tag.LastIndexOf(']');
                        int lastLeftBracket = address.Tag.LastIndexOf('[');
                        if (lastRightBracket == address.Tag.Length - 1 && lastLeftBracket != -1 && regex.Match(address.Tag.Substring(lastLeftBracket + 1, lastRightBracket - lastLeftBracket - 1)).Success)
                        {
                            int index = int.Parse(address.Tag.Substring(lastLeftBracket + 1, lastRightBracket - lastLeftBracket - 1));
                            boolTagBelongs.Add(new BoolTagBelong()
                            {
                                Name = address.ORMName,
                                Category = address.Tag.Substring(0, lastLeftBracket),
                                Index = index
                            });
                        }
                        else
                        {
                            singleBoolTags.Add(address);
                        }
                    }
                    else
                    {
                        otherTags.Add(address);
                    }
                }
                AllenBradleyNet allenBradleyNet = (AllenBradleyNet)reader;
                if (allenBradleyNet != null)
                {
                    #region bool
                    if (boolTagBelongs != null && boolTagBelongs.Count > 0)
                    {
                        foreach (var bs in boolTagBelongs.Select(v => v.Category).Distinct())
                        {
                            List<bool> array = new List<bool>();
                            OperateResult<byte[]> read = allenBradleyNet.Read(new string[] { bs });
                            if (read != null && read.IsSuccess)
                            {
                                foreach (var b in read.Content)
                                {
                                    char[] c = Convert.ToString(b, 2).PadLeft(8, '0').Reverse().ToArray();
                                    foreach (var cc in c)
                                    {
                                        array.Add(cc == '1');
                                    }
                                }
                            }
                            var bsList = boolTagBelongs.FindAll(v => v.Category.Equals(bs));
                            if (bsList != null && bs.Count() > 0 && array.Count > 0)
                            {
                                foreach (var bsl in bsList)
                                {
                                    result.Add(bsl.Name, bsl.Index < array.Count ? array[bsl.Index] : false);
                                }
                            }
                            else
                            {
                                foreach (var bsl in bsList)
                                {
                                    result.Add(bsl.Name, false);
                                }
                            }
                        }
                    }
                    #endregion
                    #region single bool
                    if (singleBoolTags != null && singleBoolTags.Count > 0)
                    {
                        foreach (var tag in singleBoolTags)
                        {
                            var sReadResult = allenBradleyNet.ReadBool(tag.Tag);
                            var sResult = sReadResult.IsSuccess ? sReadResult.Content : false;
                            result.Add(tag.ORMName, sResult);
                        }
                    }
                    #endregion
                    #region other
                    if (otherTags != null && otherTags.Count > 0)
                    {
                        var tags = otherTags.Select(v => v.Tag).Distinct().ToArray();
                        if (tags != null && tags.Length > 0)
                        {
                            try
                            {
                                OperateResult<byte[]> read = allenBradleyNet.Read(tags);
                                if (read != null && read.IsSuccess)
                                {
                                    int startIndex = 0;
                                    foreach (var t in tags)
                                    {
                                        var p = addressList.Find(v => v.Tag.Equals(t));
                                        if (p != null)
                                        {
                                            switch (p.TypeName.ToLower())
                                            {
                                                case "short":
                                                    var valShort = allenBradleyNet.ByteTransform.TransInt16(read.Content, startIndex);
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, (float)(valShort * 1.0f * p.div));
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, valShort);
                                                    }
                                                    startIndex += 2; break;
                                                case "ushort":
                                                    var valUShort = allenBradleyNet.ByteTransform.TransUInt16(read.Content, startIndex);
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, (float)(valUShort * 1.0f * p.div));
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, valUShort);
                                                    }
                                                    startIndex += 2; break;
                                                case "int":
                                                    var valInt = allenBradleyNet.ByteTransform.TransInt32(read.Content, startIndex);
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, (float)(valInt * 1.0f * p.div));
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, valInt);
                                                    }
                                                    startIndex += 4; break;
                                                case "uint":
                                                    var valUInt = allenBradleyNet.ByteTransform.TransUInt32(read.Content, startIndex);
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, (float)(valUInt * 1.0f * p.div));
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, valUInt);
                                                    }
                                                    startIndex += 4; break;
                                                case "long":
                                                    var valLong = allenBradleyNet.ByteTransform.TransInt64(read.Content, startIndex);
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, (float)(valLong * 1.0f * p.div));
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, valLong);
                                                    }
                                                    startIndex += 8; break;
                                                case "long8time":
                                                    var time = allenBradleyNet.ByteTransform.TransInt64(read.Content, startIndex);
                                                    DateTime temp = DateTime.Parse("1970-01-01");
                                                    temp = temp.AddSeconds(time - 8 * 60 * 60);
                                                    result.Add(p.ORMName, temp.ToString("yyyy-MM-dd HH:mm:ss"));
                                                    startIndex += 8;
                                                    break;
                                                case "longtime":
                                                    var time1 = allenBradleyNet.ByteTransform.TransInt64(read.Content, startIndex);
                                                    DateTime temp1 = DateTime.Parse("1970-01-01");
                                                    temp1 = temp1.AddSeconds(time1);
                                                    result.Add(p.ORMName, temp1.ToString("yyyy-MM-dd HH:mm:ss"));
                                                    startIndex += 8;
                                                    break;
                                                case "ulong":
                                                    var valULong = allenBradleyNet.ByteTransform.TransUInt64(read.Content, startIndex);
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, (float)(valULong * 1.0f * p.div));
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, valULong);
                                                    }
                                                    startIndex += 8; break;
                                                case "decimal":
                                                case "float":
                                                    var valFloat = allenBradleyNet.ByteTransform.TransSingle(read.Content, startIndex);
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, (float)(valFloat * 1.0f * p.div));
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, valFloat);
                                                    }
                                                    startIndex += 4; break;
                                                case "double":
                                                    var valDouble = allenBradleyNet.ByteTransform.TransDouble(read.Content, startIndex);
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, (double)(valDouble * 1.0f * p.div));
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, valDouble);
                                                    }
                                                    startIndex += 8; break;
                                                case "byte": result.Add(p.ORMName, allenBradleyNet.ByteTransform.TransByte(read.Content, startIndex)); startIndex += 1; break;
                                                case "string":
                                                    short len = allenBradleyNet.ByteTransform.TransInt16(read.Content, startIndex);
                                                    startIndex += 2;
                                                    if (len > 0 && read.Content.Length >= (startIndex + len))
                                                    {
                                                        byte[] buffer = read.Content.Skip(startIndex).Take(len).ToArray();
                                                        string str = this.mEncoding.GetString(buffer);
                                                        result.Add(p.ORMName, str);
                                                        startIndex += len; //加上原有定义的类型长度
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, string.Empty);
                                                    }
                                                    break;
                                            }
                                        }
                                    }
                                }
                                else
                                {
                                    LogHelper.Warn($"{string.Join(",", tags)}，没有得到数据【{(read != null ? read.Message : "")}】");
                                    foreach (var t in tags)
                                    {
                                        var p = addressList.Find(v => v.Tag.Equals(t));
                                        if (p != null)
                                        {
                                            switch (p.TypeName.ToLower())
                                            {
                                                case "short":
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, 0.0f);
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, (short)0);
                                                    }
                                                    break;
                                                case "ushort":
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, 0.0f);
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, (ushort)0);
                                                    }
                                                    break;
                                                case "int":
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, 0.0f);
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, (int)0);
                                                    }
                                                    break;
                                                case "uint":
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, 0.0f);
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, (uint)0);
                                                    }
                                                    break;
                                                case "long":
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, 0.0f);
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, (long)0);
                                                    }
                                                    break;
                                                case "long8time":
                                                case "longtime":
                                                    result.Add(p.ORMName, "1970-01-01 00:00:00");
                                                    break;
                                                case "ulong":
                                                    if (p.IsToFloat)
                                                    {
                                                        result.Add(p.ORMName, 0.0f);
                                                    }
                                                    else
                                                    {
                                                        result.Add(p.ORMName, (ulong)0);
                                                    }
                                                    break;
                                                case "decimal":
                                                case "float": result.Add(p.ORMName, 0.0f); break;
                                                case "double": result.Add(p.ORMName, (double)0); break;
                                                case "byte": result.Add(p.ORMName, (byte)0); break;
                                                case "string": result.Add(p.ORMName, ""); break;
                                            }
                                        }
                                    }
                                }
                            }
                            catch (Exception innerEx)
                            {
                                LogHelper.Error(innerEx);
                            }
                        }
                    }
                    #endregion
                }
            }
            return result;
        }
        /// <summary>
        /// 只支持地址
        /// </summary>
        /// <param name="addressList"></param>
        /// <returns></returns>
        private Dictionary<string, object> BatchAddressRead(List<PLCTagSetting> addressList)
        {
            var reader = this.GetBatchReader();

            Dictionary<string, object> result = new Dictionary<string, object>();
            if (reader != null && addressList != null && addressList.Count > 0)
            {
                try
                {
                    var boolCount = addressList.Count(v => v.TypeName.ToLower().Equals("bool"));
                    var specialMelsec = this.mPLCEntity.OptType == EPLCOptType.FINS && this.mPLCEntity.DeviceType == EPLCDeviceType.MELSEC && boolCount == addressList.Count;

                    var temp = addressList[0];
                    Regex regex = new Regex("[0-9]");
                    var match = regex.Match(temp.Tag);
                    if (match.Success && match.Index != -1)
                    {
                        var allAddress = new List<int>();
                        foreach (var v in addressList)
                        {
                            string numPart = v.Tag.Substring(match.Index);
                            int numIndex = numPart.IndexOf(".");
                            if (numIndex != -1)
                            {
                                numPart = numPart.Substring(0, numIndex);
                            }
                            int num = 0;
                            if (!string.IsNullOrWhiteSpace(numPart) && int.TryParse(numPart, out num))
                            {
                                if (!allAddress.Contains(num))
                                {
                                    allAddress.Add(num);
                                }
                            }
                        }
                        var maxAddress = allAddress.Max();
                        var minAddress = allAddress.Min();
                        var tagAddress = temp.Tag.Substring(0, match.Index);
                        var startAddress = $"{tagAddress}{minAddress}";
                        ushort readLength = (ushort)(maxAddress - minAddress + 90);
                        if (specialMelsec)
                        {
                            var tempLength = maxAddress - minAddress;
                            readLength = (ushort)(tempLength / 8 + (tempLength % 8 > 0 ? 1 : 0));
                        }
                        OperateResult<byte[]> read = reader.Read(startAddress, readLength);
                        if (read != null && read.IsSuccess && read.Content != null && read.Content.Length > 0)
                        {
                            if (specialMelsec)
                            {
                                StringBuilder sb = new StringBuilder();
                                foreach (var item in read.Content)
                                {
                                    sb.Append(string.Join("", Convert.ToString(item, 2).PadLeft(8, '0').Reverse()));
                                }
                                string boolContent = sb.ToString();
                                List<bool> boolList = new List<bool>();
                                for (var i = 0; i < boolContent.Length; i++)
                                {
                                    boolList.Add(boolContent[i] == '1');
                                }
                                foreach (var p in addressList)
                                {
                                    string numAddress = p.Tag.Substring(match.Index);
                                    int intAddress = int.Parse(numAddress);
                                    int startIndex = intAddress - minAddress;
                                    if (startIndex < boolList.Count)
                                    {
                                        result.Add(p.ORMName, boolList[startIndex]);
                                    }
                                    else
                                    {
                                        result.Add(p.ORMName, false);
                                    }
                                }
                            }
                            else
                            {
                                foreach (var p in addressList)
                                {
                                    int intAddress = -1;
                                    string numAddress = p.Tag.Substring(match.Index);
                                    int numIndex = numAddress.IndexOf(".");
                                    int decValue = -1;
                                    if (numIndex == -1)
                                    {
                                        intAddress = int.Parse(numAddress);
                                    }
                                    else
                                    {
                                        intAddress = int.Parse(numAddress.Substring(0, numIndex));
                                        decValue = int.Parse(numAddress.Substring(numIndex + 1));
                                    }
                                    int startIndex = (intAddress - minAddress) * 2;
                                    switch (p.TypeName.ToLower())
                                    {
                                        case "short":
                                            var valShort = reader.ByteTransform.TransInt16(read.Content, startIndex);
                                            if (p.IsToFloat)
                                            {
                                                result.Add(p.ORMName, (float)(valShort * 1.0f * p.div));
                                            }
                                            else
                                            {
                                                result.Add(p.ORMName, valShort);
                                            }
                                            break;
                                        case "ushort":
                                            var valUShort = reader.ByteTransform.TransUInt16(read.Content, startIndex);
                                            if (p.IsToFloat)
                                            {
                                                result.Add(p.ORMName, (float)(valUShort * 1.0f * p.div));
                                            }
                                            else
                                            {
                                                result.Add(p.ORMName, valUShort);
                                            }
                                            break;
                                        case "int":
                                            var valInt = reader.ByteTransform.TransInt32(read.Content, startIndex);
                                            if (p.IsToFloat)
                                            {
                                                result.Add(p.ORMName, (float)(valInt * 1.0f * p.div));
                                            }
                                            else
                                            {
                                                result.Add(p.ORMName, valInt);
                                            }
                                            break;
                                        case "uint":
                                            var valUInt = reader.ByteTransform.TransUInt32(read.Content, startIndex);
                                            if (p.IsToFloat)
                                            {
                                                result.Add(p.ORMName, (float)(valUInt * 1.0f * p.div));
                                            }
                                            else
                                            {
                                                result.Add(p.ORMName, valUInt);
                                            }
                                            break;
                                        case "long":
                                            var valLong = reader.ByteTransform.TransInt64(read.Content, startIndex);
                                            if (p.IsToFloat)
                                            {
                                                result.Add(p.ORMName, (float)(valLong * 1.0f * p.div));
                                            }
                                            else
                                            {
                                                result.Add(p.ORMName, valLong);
                                            }
                                            break;
                                        case "ulong":
                                            var valULong = reader.ByteTransform.TransUInt64(read.Content, startIndex);
                                            if (p.IsToFloat)
                                            {
                                                result.Add(p.ORMName, (float)(valULong * 1.0f * p.div));
                                            }
                                            else
                                            {
                                                result.Add(p.ORMName, valULong);
                                            }
                                            break;
                                        case "long8time":
                                            var time = reader.ByteTransform.TransInt64(read.Content, startIndex);
                                            DateTime tempTime = DateTime.Parse("1970-01-01");
                                            tempTime = tempTime.AddSeconds(time - 8 * 60 * 60);
                                            result.Add(p.ORMName, tempTime.ToString("yyyy-MM-dd HH:mm:ss"));
                                            break;
                                        case "longtime":
                                            var time1 = reader.ByteTransform.TransInt64(read.Content, startIndex);
                                            DateTime tempTime1 = DateTime.Parse("1970-01-01");
                                            tempTime1 = tempTime1.AddSeconds(time1);
                                            result.Add(p.ORMName, tempTime1.ToString("yyyy-MM-dd HH:mm:ss"));
                                            break;
                                        case "decimal":
                                        case "float":
                                            var valFloat = reader.ByteTransform.TransSingle(read.Content, startIndex);
                                            if (p.IsToFloat)
                                            {
                                                result.Add(p.ORMName, (float)(valFloat * 1.0f * p.div));
                                            }
                                            else
                                            {
                                                result.Add(p.ORMName, valFloat);
                                            }
                                            break;
                                        case "double":
                                            var valDouble = reader.ByteTransform.TransDouble(read.Content, startIndex);
                                            if (p.IsToFloat)
                                            {
                                                result.Add(p.ORMName, (double)(valDouble * 1.0f * p.div));
                                            }
                                            else
                                            {
                                                result.Add(p.ORMName, valDouble);
                                            }
                                            break;
                                        case "byte": result.Add(p.ORMName, reader.ByteTransform.TransByte(read.Content, startIndex)); break;
                                        case "bool":
                                            if (decValue == -1)
                                            {
                                                result.Add(p.ORMName, reader.ByteTransform.TransInt16(read.Content, startIndex) == 1);
                                            }
                                            else if (decValue >= 0 && decValue <= 15)
                                            {
                                                var charArray = $"{Convert.ToString(read.Content[startIndex], 2).PadLeft(8, '0')}{Convert.ToString(read.Content[startIndex + 1], 2).PadLeft(8, '0')}".Reverse().ToList();
                                                result.Add(p.ORMName, charArray[decValue] == '1');
                                            }
                                            break;
                                        case "string": result.Add(p.ORMName, CommonHelper.ReplaceString(reader.ByteTransform.TransString(read.Content, startIndex, (int)(Math.Round(p.len / 2.0) * 2), this.mEncoding))); break;
                                    }
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex, "", CommonHelper.GetJsonString(addressList));
                }
            }
            return result;
        }
        /// <summary>
        /// 读值
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public List<string> Read(EDataType dataType, string address, ushort length = 1)
        {
            List<string> list = new List<string>();
            switch (dataType)
            {
                case EDataType.BOOL:
                    var boolContents = ReadBool(address, length);
                    if (boolContents != null && boolContents.Length > 0)
                    {
                        list.AddRange(boolContents.Select(v => v.ToString()));
                    }
                    break;
                case EDataType.DOUBLE:
                    var doubleContents = ReadDouble(address, length);
                    if (doubleContents != null && doubleContents.Length > 0)
                    {
                        list.AddRange(doubleContents.Select(v => v.ToString()));
                    }
                    break;
                case EDataType.FLOAT:
                    var floatContents = ReadFloat(address, length);
                    if (floatContents != null && floatContents.Length > 0)
                    {
                        list.AddRange(floatContents.Select(v => v.ToString()));
                    }
                    break;
                case EDataType.INT:
                    var intContents = ReadInt(address, length);
                    if (intContents != null && intContents.Length > 0)
                    {
                        list.AddRange(intContents.Select(v => v.ToString()));
                    }
                    break;
                case EDataType.LONG:
                    var longContents = ReadLong(address, length);
                    if (longContents != null && longContents.Length > 0)
                    {
                        list.AddRange(longContents.Select(v => v.ToString()));
                    }
                    break;
                case EDataType.SHORT:
                    var shortContents = ReadShort(address, length);
                    if (shortContents != null && shortContents.Length > 0)
                    {
                        list.AddRange(shortContents.Select(v => v.ToString()));
                    }
                    break;
                case EDataType.STRING:
                    var stringContents = ReadString(address, length);
                    if (stringContents != null && !string.IsNullOrWhiteSpace(stringContents))
                    {
                        list.Add(stringContents);
                    }
                    break;
                case EDataType.UINT:
                    var uintContents = ReadUInt(address, length);
                    if (uintContents != null && uintContents.Length > 0)
                    {
                        list.AddRange(uintContents.Select(v => v.ToString()));
                    }
                    break;
                case EDataType.ULONG:
                    var ulongContens = ReadULong(address, length);
                    if (ulongContens != null && ulongContens.Length > 0)
                    {
                        list.AddRange(ulongContens.Select(v => v.ToString()));
                    }
                    break;
                case EDataType.USHORT:
                    var ushortContents = ReadUShort(address, length);
                    if (ushortContents != null && ushortContents.Length > 0)
                    {
                        list.AddRange(ushortContents.Select(v => v.ToString()));
                    }
                    break;
            }
            return list;
        }
        /// <summary>
        /// 读Byte
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public byte ReadByte(string address)
        {
            var result = ReadByte(address, 1);
            if (result == null || result.Length == 0)
            {
                return (byte)0;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读Short
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public short ReadShort(string address)
        {
            var result = ReadShort(address, 1);
            if (result == null || result.Length == 0)
            {
                return (short)0;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读UShort
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public ushort ReadUShort(string address)
        {
            var result = ReadUShort(address, 1);
            if (result == null || result.Length == 0)
            {
                return (ushort)0;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读Int
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public int ReadInt(string address)
        {
            var result = ReadInt(address, 1);
            if (result == null || result.Length == 0)
            {
                return (int)0;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读UInt
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public uint ReadUInt(string address)
        {
            var result = ReadUInt(address, 1);
            if (result == null || result.Length == 0)
            {
                return (uint)0;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读Long
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public long ReadLong(string address)
        {
            var result = ReadLong(address, 1);
            if (result == null || result.Length == 0)
            {
                return (long)0;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读ULong
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public ulong ReadULong(string address)
        {
            var result = ReadULong(address, 1);
            if (result == null || result.Length == 0)
            {
                return (ulong)0;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读Float
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public float ReadFloat(string address)
        {
            var result = ReadFloat(address, 1);
            if (result == null || result.Length == 0)
            {
                return 0.00f;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读Double
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public double ReadDouble(string address)
        {
            var result = ReadDouble(address, 1);
            if (result == null || result.Length == 0)
            {
                return (double)0;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读Bool
        /// </summary>
        /// <param name="address"></param>
        /// <returns></returns>
        public bool ReadBool(string address)
        {
            var result = ReadBool(address, 1);
            if (result == null || result.Length == 0)
            {
                return false;
            }
            else
            {
                return result[0];
            }
        }
        /// <summary>
        /// 读Byte
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public byte[] ReadByte(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            byte[] result = new byte[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.Read(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读Short
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public short[] ReadShort(string address, ushort length = 1)
        {
#if DEBUG
            LogHelper.Debug($"【ReadShort】 开始：{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}，{address}");
#endif
            var reader = this.GetReader();
            short[] result = new short[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadInt16(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
#if DEBUG
            LogHelper.Debug($"【ReadShort】 结束：{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss.fff")}，{address}");
#endif
            return result;
        }
        /// <summary>
        /// 读UShort
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public ushort[] ReadUShort(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            ushort[] result = new ushort[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadUInt16(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读Int
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public int[] ReadInt(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            int[] result = new int[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadInt32(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读UInt
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public uint[] ReadUInt(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            uint[] result = new uint[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadUInt32(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读Long
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public long[] ReadLong(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            long[] result = new long[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadInt64(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读ULong
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public ulong[] ReadULong(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            ulong[] result = new ulong[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadUInt64(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读Float
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public float[] ReadFloat(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            float[] result = new float[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadFloat(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读Double
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public double[] ReadDouble(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            double[] result = new double[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadDouble(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读Bool
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public bool[] ReadBool(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            bool[] result = new bool[length];
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    var array = reader.ReadBool(address, length);
                    if (array != null && array.IsSuccess && array.Content != null && array.Content.Length == length)
                    {
                        result = array.Content;
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 读字符串
        /// </summary>
        /// <param name="address"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public string ReadString(string address, ushort length = 1)
        {
            var reader = this.GetReader();
            string result = "";
            if (reader != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    result = reader.ReadString(address, length, this.mEncoding).Content;
                    result = CommonHelper.ReplaceString(result);
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            return result;
        }
        /// <summary>
        /// 写值
        /// </summary>
        /// <param name="dataType"></param>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <returns></returns>
        public (bool result, string message) Write(EDataType dataType, string address, string value)
        {
            var writer = this.GetWriter();
            bool result = false;
            string message = "";
            try
            {
                if (writer != null)
                {
                    switch (dataType)
                    {
                        case EDataType.BOOL:
                            result = writer.Write(address, bool.Parse(value)).IsSuccess;
                            break;
                        case EDataType.DOUBLE:
                            result = writer.Write(address, double.Parse(value)).IsSuccess;
                            break;
                        case EDataType.FLOAT:
                            result = writer.Write(address, float.Parse(value)).IsSuccess;
                            break;
                        case EDataType.INT:
                            result = writer.Write(address, int.Parse(value)).IsSuccess;
                            break;
                        case EDataType.LONG:
                            result = writer.Write(address, long.Parse(value)).IsSuccess;
                            break;
                        case EDataType.SHORT:
                            result = writer.Write(address, short.Parse(value)).IsSuccess;
                            break;
                        case EDataType.STRING:
                            result = writer.Write(address, value, this.mEncoding).IsSuccess;
                            break;
                        case EDataType.UINT:
                            result = writer.Write(address, uint.Parse(value)).IsSuccess;
                            break;
                        case EDataType.ULONG:
                            result = writer.Write(address, ulong.Parse(value)).IsSuccess;
                            break;
                        case EDataType.USHORT:
                            result = writer.Write(address, ushort.Parse(value)).IsSuccess;
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                message = ex.Message;
                LogHelper.Error(ex);
            }
            return (result, message);
        }
        /// <summary>
        /// 写值
        /// 0 - 正常，1~10 - H3153, 11~15 - 5520（Multiple 有效）
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="address"></param>
        /// <param name="value"></param>
        /// <param name="doubleCheck"></param>
        /// <param name="writerType">0 - 正常，1 - H3153, 2 - 5520（Multiple 有效）</param>
        public void Write<T>(string address, T value, bool doubleCheck = true, int writerType = 0)
        {
            var writer = this.GetWriter(writerType);
            OperateResult result = new OperateResult()
            {
                IsSuccess = false
            };
            if (writer != null && !string.IsNullOrWhiteSpace(address))
            {
                try
                {
                    string typeName = value.GetType().Name;
                    switch (typeName)
                    {
                        case "Int16": result = writer.Write(address, Int16.Parse($"{value}")); break;
                        case "UInt16": result = writer.Write(address, UInt16.Parse($"{value}")); break;
                        case "Int32": result = writer.Write(address, Int32.Parse($"{value}")); break;
                        case "UInt32": result = writer.Write(address, UInt32.Parse($"{value}")); break;
                        case "Int64": result = writer.Write(address, Int64.Parse($"{value}")); break;
                        case "UInt64": result = writer.Write(address, UInt64.Parse($"{value}")); break;
                        case "Single": result = writer.Write(address, float.Parse($"{value}")); break;
                        case "Double": result = writer.Write(address, double.Parse($"{value}")); break;
                        case "Decimal": result = writer.Write(address, float.Parse($"{value}")); break;
                        case "Byte": result = writer.Write(address, byte.Parse($"{value}")); break;
                        case "String": result = writer.Write(address, $"{value}", this.mEncoding); break;
                        case "Boolean": result = writer.Write(address, bool.Parse($"{value}")); break;
                        case "Int16[]": result = writer.Write(address, value as Int16[]); break;
                        case "UInt16[]": result = writer.Write(address, value as UInt16[]); break;
                        case "Int32[]": result = writer.Write(address, value as Int32[]); break;
                        case "UInt32[]": result = writer.Write(address, value as UInt32[]); break;
                        case "Int64[]": result = writer.Write(address, value as Int64[]); break;
                        case "UInt64[]": result = writer.Write(address, value as UInt64[]); break;
                        case "Single[]": result = writer.Write(address, value as Single[]); break;
                        case "Double[]": result = writer.Write(address, value as Double[]); break;
                        case "Decimal[]": result = writer.Write(address, value as float[]); break;
                        case "Byte[]": result = writer.Write(address, value as Byte[]); break;
                        case "Boolean[]": result = writer.Write(address, value as Boolean[]); break;
                    }
                    if (doubleCheck && !result.IsSuccess)
                    {
                        LogHelper.Info($"【二次写值】{address}：{value}");
                        Write(address, value, false);
                    }
                }
                catch (Exception ex)
                {
                    LogHelper.Error(ex);
                }
            }
            else if (writer == null)
            {
                LogHelper.Warn($"PLC连接不正确，写入地址：{address}，写入值：{value}");
            }
        }
        /// <summary>
        /// 并发写值
        /// </summary>
        /// <param name="values"></param>
        public void ParallelWrite(Dictionary<string, object> values)
        {
            if (values != null && values.Count > 0)
            {
                Task.Run(() =>
                {
                    try
                    {
                        Parallel.ForEach(values, (v, k) =>
                        {
                            Write(v.Key, v.Value);
                        });
                    }
                    catch (Exception ex)
                    {
                        LogHelper.Error(ex);
                    }
                });
            }
        }
    }
}
